package cn.tedu._07springaop.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.lang.reflect.Array;
import java.util.Arrays;

/**
 * @Author Justin Parker
 * @Date 2024/8/15 0015 9:25
 * @Version 1.0
 */
/*
    @Aspect 注解：
        1.标识该类为切面类；
        2.当开发者在调用目标方法时，切面类中的方法会自动执行；
 */
@Aspect
@Component
public class LogAspect {

//    @Before(value = "execution(public int cn.tedu._07springaop.aop.CalculatorImpl.*(..))")
//    public void beforeMethod(JoinPoint joinPoint){
//        /*
//            JoinPoint参数：连接点对象，被拦截的目标方法
//            1.获取目标方法名
//            2.获取目标方法的参数
//         */
//        String name = joinPoint.getSignature().getName();
//        String args = Arrays.toString(joinPoint.getArgs());
//        System.out.println(name+"方法开始，参数为："+args);
//    }

    /*
        @AfterReturning注解：返回值，目标方法成为结束后执行
            2.1 权限：可以获取目标方法的返回值；
     */
//    @AfterReturning(value = "execution(public  int cn.tedu._07springaop.aop.CalculatorImpl.*(..))",returning = "r")
//    public void afterReturningMethod(JoinPoint joinPoint,Object r){
//        String name = joinPoint.getSignature().getName();
//        System.out.println(name+"方法执行完毕,结果为："+r);
//    }

    /**
     * 3.@AfterThrowing注解：异常，目标方法抛出异常时执行
     */
//    @AfterThrowing(value = "execution(public  int cn.tedu._07springaop.aop.CalculatorImpl.*(..))",throwing = "e")
//    public void afterThrowingMethod(JoinPoint joinPoint,Exception e){
//        String name = joinPoint.getSignature().getName();
//        System.out.println("3.异常通知："+name+"方法抛出异常，异常信息为："+e.getMessage());
//    }

    /*
        4.@After注解：后置通知，目标方法执行完毕，无论目标方法抛出异常与否，都会执行
            后置通知和返回通知的区别：
            1.返回通知在目标方法成功结束后执行，后置通知成功结束和异常结果都会执行；
            2.返回通知可以获取目标方法的返回值，后置通知不可以获取目标方法的返回值；
     */
//    @After(value ="execution(public int cn.tedu._07springaop.aop.CalculatorImpl.*(..))")
//    public void afterMethod(JoinPoint joinPoint){
//        String name = joinPoint.getSignature().getName();
//        System.out.println("4.后置通知："+name+"方法执行完毕");
//    }

    /*
        5.@Around注解：环绕通知；
        等价于：前置通知+返回通知+异常通知+后置通知；
     */
    @Around(value ="execution(public int cn.tedu._07springaop.aop.CalculatorImpl.*(..))")
    public Object aroundMethod(ProceedingJoinPoint joinPoint){

        Object result = null;

        try{
            /*
                1.前置通知；
                2.调用目标方法；
                3.返回通知
             */

            System.out.println("环绕通知：前置通知");
            result = joinPoint.proceed();
            System.out.println("环绕通知：返回通知");
        } catch (Throwable e) {
            System.out.println("环绕通知：异常通知");
            throw new RuntimeException(e);
        }finally{
            System.out.println("环绕通知：后置通知");
        }
        return result;
    }
}
